<?php
/**
 * Copyright (c) 2009, Sword Page <http://www.swordpage.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the Sword Page nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */


class Sword_App
{
    protected static $_instance = null;

    private function __construct()
    {
        $this->_initApp();
    }

    private function __clone() {}

    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function run()
    {
        $this->_setupEnvironment()
             ->_setupDb()
             ->_setupFrontController()
             ->_setupAcl()
             ->_setupViews()
             ->_setupCache()
             ->_setupTranslation()
             ->_dispatchFrontController();
        return $this;
    }

    public function getPath($key)
    {
        if (isset($this->_paths[$key])) {
            return $this->_paths[$key];
        } else {
            return null;
        }
    }

    protected function _initApp()
    {
        if (!defined('APP_NAME')) {
            define('APP_NAME', 'application');
        }
        if (!defined('SWORD_DS')) {
            define('SWORD_DS', DIRECTORY_SEPARATOR);
        }
        if (!defined('SWORD_PS')) {
            define('SWORD_PS', PATH_SEPARATOR);
        }
        if (!defined('BASE_PATH')) {
            define('BASE_PATH', dirname(dirname(dirname(__FILE__))) . SWORD_DS);
        }
        if (!defined('TMP_PATH')) {
            define('TMP_PATH', BASE_PATH . 'tmp' . SWORD_DS);
        }
        if (!defined('APP_PATH')) {
            define('APP_PATH', BASE_PATH . APP_NAME . SWORD_DS);
        }
        if (!defined('MODEL_PATH')) {
            define('MODEL_PATH', APP_PATH . 'models' . SWORD_DS);
        }
        if (!defined('VIEW_PATH')) {
            define('VIEW_PATH', APP_PATH . 'views' . SWORD_DS);
        }
        if (!defined('CONFIG_PATH')) {
            define('CONFIG_PATH', APP_PATH . 'config' . SWORD_DS);
        }
        if (!defined('CONTROLLER_PATH')) {
            define('CONTROLLER_PATH', APP_PATH . 'controllers' . SWORD_DS);
        }
        if (!defined('LAYOUT_PATH')) {
            define('LAYOUT_PATH', APP_PATH . 'layouts' . SWORD_DS);
        }
        if (!defined('LIB_PATH')) {
            define('LIB_PATH', BASE_PATH . 'library' . SWORD_DS);
        }
        return $this;
    }

    protected function _setupEnvironment()
    {
        error_reporting(E_ALL | E_STRICT);
        $includePath = array();
        $includePath[] = get_include_path();
        $includePath[] = LIB_PATH;
        $includePath[] = MODEL_PATH;
        set_include_path(implode(SWORD_PS, $includePath));

        require_once 'Zend/Loader.php';
        Zend_Loader::registerAutoLoad();

        // start session, use tmp by default
        session_save_path(TMP_PATH);
        Zend_Session::start();

        if (!defined('APP_ENV')) {
            define('APP_ENV', 'production');
        }
        $config = new Zend_Config_Ini(CONFIG_PATH . 'app.ini', APP_ENV);
        Zend_Registry::set('config', $config);
        try {
            date_default_timezone_set($config->date->timezone);
        } catch (Zend_Exception $e) {
            die($e->getMessage());
        }
        return $this;
    }

    protected function _setupAutoloader()
    {
        return $this;
    }

    protected function _loadConfig()
    {
        return $this;
    }

    protected function _setupDb()
    {
        try {
            $config = Zend_Registry::get('config');
            $dbAdapter = Zend_Db::factory($config->database);
            $dbAdapter->query("SET NAMES 'utf8'");
        } catch (Zend_Exception $e) {
            die ($e->getMessage());
        }
        Zend_Db_Table_Abstract::setDefaultAdapter($dbAdapter);
        Zend_Registry::set('dbAdapter',$dbAdapter);
        return $this;
    }

    protected function _setupFrontController()
    {
        $layoutContext = new Sword_Controller_Plugin_Dispatch_LayoutContext();
        $checkAuth = new Sword_Controller_Plugin_Dispatch_CheckAuth();
        $check = new Sword_Controller_Plugin_Dispatch_Check();
        $frontController = Zend_Controller_Front::getInstance();
        $frontController->throwExceptions(true)
                        ->setControllerDirectory(CONTROLLER_PATH)
                        ->registerPlugin($layoutContext)
                        //->registerPlugin($checkAuth)
                        //->registerPlugin($check)
                        ->returnResponse(true);
        Zend_Layout::startMvc(LAYOUT_PATH . 'scripts');
        return $this;
    }

    protected function _setupViews()
    {
        $view = Zend_Layout::getMvcInstance()->getView();
        Zend_Dojo::enableView($view);
        return $this;
    }

    protected function _dispatchFrontController()
    {
        $frontController = Zend_Controller_Front::getInstance();
        try {
            try {
                $frontController->dispatch()
                                ->sendResponse();
            } catch (Zend_Exception $ze) {
                    die($ze->getMessage());
                try {
                    $loginRequest = new Zend_Controller_Request_Http();
                    $loginRequest->setControllerName('login')
                                 ->setActionName('index');
                    $router = new Zend_Controller_Router_Route('login/:index');
                    $frontController->getRouter()
                                    ->removeDefaultRoutes()
                                    ->addRoute('default', $router);
                    $frontController->setRequest($loginRequest)
                                    ->dispatch()
                                    ->sendResponse();
                } catch (Zend_Exception $ze2) {
                    die($ze2->getMessage());
                }
            }
        } catch (Exception $e) {
            $msg = 'HTTP/1.1 500 Server Error';
            $frontController->getResponse()->setRawHeader($msg);
            echo $e->getMessage();
        }
        return $this;
    }

    protected function _setupCache()
    {
        $frontendOptions = array();
        $frontendOptions['lifetime'] = 3600;
        $frontendOptions['automatic_serialization'] = true;

        $backendOptions = array();
        $backendOptions['file_name_prefix'] = 'sword';
        $backendOptions['hashed_directory_level'] = 1;
        $backendOptions['cache_dir'] = TMP_PATH;
        $backendOptions['hashed_directory_umask'] = 0700;
        $cache = Zend_Cache::factory('Core', 'File', $frontendOptions, 
                                                     $backendOptions);
        Zend_Registry::set('cache', $cache);
        return $this;
    }

    protected function _setupTranslation()
    {
        /* comment-out temporarily
        $cache = Zend_Registry::get('cache');
        Zend_Translate::setCache($cache);
        require_once('english.php');
        $translate = new Zend_Translate('array', $english, 'en');
        Zend_Registry::set('translate', $translate);
         */
        return $this;
    }

    protected function _setupAcl()
    {
        return $this;
    }

}

